import logging

from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import float_compare

_logger = logging.getLogger(__name__)


class StockWarehouseRequisitionpoint(models.Model):
    _name = "stock.warehouse.requisitionpoint"
    _description = "Stock Warehouse Requisition Point"

    name = fields.Char(
        'Name', copy=False, required=True, readonly=True,
        default=lambda self: self.env['ir.sequence'].next_by_code('stock.requisitionpoint'))
    trigger = fields.Selection([
        ('auto', 'Auto'), ('manual', 'Manual')], string='Trigger', default='auto', required=True)
    active = fields.Boolean('Active', default=True)
    warehouse_id = fields.Many2one(
        'stock.warehouse', 'Warehouse',
        compute="_compute_warehouse_id", store=True, readonly=False, precompute=True,
        check_company=True, ondelete="cascade", required=True)

    location_id = fields.Many2one(
        'stock.location', 'Location', index=True,
        compute="_compute_location_id", store=True, readonly=False, precompute=True,
        ondelete="cascade", required=True, check_company=True)
    company_id = fields.Many2one(
        'res.company', 'Company', required=True, index=True,
        default=lambda self: self.env.company)
    snoozed_until = fields.Date('Snoozed')
    product_id = fields.Many2one(
        'product.product', 'Product', domain=[('type', '=', 'product')],
        ondelete='cascade', required=True, check_company=True, index=True
    )
    product_tmpl_id = fields.Many2one('product.template', related='product_id.product_tmpl_id')
    product_category_id = fields.Many2one(
        'product.category', name='Product Category', related='product_id.categ_id', store=True)
    stock_product_uom = fields.Many2one('uom.uom', 'Unit of Stock', related='product_id.uom_id')
    stock_product_uom_name = fields.Char(
        string='Product unit of Stock label', related='stock_product_uom.display_name', readonly=True)
    product_uom = fields.Many2one('uom.uom', 'Unit of purchase', related='product_id.uom_po_id')
    product_uom_name = fields.Char(
        string='Product unit of purchase label', related='product_uom.display_name', readonly=True)
    product_min_qty = fields.Float('Min quantity', digits='Product Unit of Measure', required=True, default=0.0)
    product_max_qty = fields.Float('Max quantity', digits='Product Unit of Measure', required=True, default=0.0)
    qty_multiple = fields.Float('Multiple quantity', digits='Product Unit of Measure', default=1, required=True)
    route_id = fields.Many2one(
        'stock.route', string='Route',
        domain="[('product_selectable', '=', True), ('rule_ids.action', 'in', ['buy'])]")
    # 库存总数量
    qty_available = fields.Float('Qty Available', related='product_id.s_actual_quantity', digits='Product Unit of Measure')
    # 订购数量
    qty_to_order = fields.Float('To Order', readonly=False, digits='Product Unit of Measure')
    update_to_order = fields.Float(
        'Uodate To Order', compute='compute_qty_to_order', digits='Product Unit of Measure')
    transit_qty = fields.Float('Transit Qty', readonly=True)
    hide_attachments_filename = fields.Char(string="Attachment Name")
    hide_attachments_file = fields.Binary(
        attachment=True,
        string="Attachment File",
    )

    minimum_warnings_qty = fields.Float(string='Minimum number of warnings', digits='Product Unit of Measure', default=0.0)
    warnings = fields.Boolean(string='Warnings', compute='_compute_warnings', store=True)
    # requisition_ids = fields.One2many('purchase.requisition', 'orderpoint_id', string='Requisition')

    @api.depends('qty_to_order', 'minimum_warnings_qty')
    def _compute_warnings(self):
        for rec in self:
            if float_compare(rec.qty_to_order, rec.minimum_warnings_qty, 3) >= 0:
                rec.warnings = True
            else:
                rec.warnings = False

    @api.depends('warehouse_id', 'company_id')
    def _compute_location_id(self):
        """ 查找仓库位置 """
        for orderpoint in self:
            warehouse = orderpoint.warehouse_id
            if not warehouse:
                warehouse = orderpoint.env['stock.warehouse'].search([
                    ('company_id', '=', orderpoint.company_id.id)
                ], limit=1)
            orderpoint.location_id = warehouse.lot_stock_id.id
            route = self.env['stock.route'].search(
                [('product_selectable', '=', True), ('rule_ids.action', 'in', ['buy'])], limit=1)
            orderpoint.route_id = route.id

    @api.depends('location_id', 'company_id')
    def _compute_warehouse_id(self):
        for orderpoint in self:
            if orderpoint.location_id.warehouse_id:
                orderpoint.warehouse_id = orderpoint.location_id.warehouse_id
            elif orderpoint.company_id:
                orderpoint.warehouse_id = orderpoint.env['stock.warehouse'].search([
                    ('company_id', '=', orderpoint.company_id.id)
                ], limit=1)

    @api.depends('product_id', 'qty_available', 'product_min_qty', 'qty_multiple', 'minimum_warnings_qty')
    def compute_qty_to_order(self):
        """计算订购数量
        1. 在请购单中获取已经下单数量
        2. 验证是否入库, 减去入库数量
        订购数量 = 最小数量 * 倍数 - 库存数量
        订购数量 > 最大数量 |= 最大数量
        """
        for record in self:
            record.update_to_order = 0
            CHECK_ORDERPOINT_CODE = False
            # 正在订购未完成的数量, 已经下单,但是还未入库, 排除已完成的
            pr_domain = [
                ('product_id', '=', record.product_tmpl_id.id),
                ('requisition_id.purchase_requisition_type', '=', 'material'),
                ('requisition_id.state', 'in', ['approved', 'section_purchasing', 'purchasing', 'done']),
                ('state', 'not in', ['closed', 'done'])
            ]
            close_pr_domain = [
                ('product_id', '=', record.product_tmpl_id.id),
                ('requisition_id.purchase_requisition_type', '=', 'material'),
                ('requisition_id.state', '=', 'closed'),
                ('state', '=', 'closed')
            ]
            close_pr_line_list = self.env['purchase.requisition.line']._read_group(close_pr_domain, ['id'],
                                                                                   ['product_qty:sum'])
            close_pr_line_dict = {pr.id: val for pr, val in close_pr_line_list}
            pr_line_list = self.env['purchase.requisition.line']._read_group(pr_domain, ['id'], ['product_qty:sum'])
            pr_line_dict = {pr.id: val for pr, val in pr_line_list}
            # 下单数量
            pr_product_qty = round(sum(pr_line_dict.values(), 0), 4)

            # 进一步获取采购单入库订单
            pl_domain = [
                ('pr_middle_ids.pr_line_id', 'in', list(pr_line_dict.keys())),
                ('state', '!=', 'cancel'),
                ('product_id', '=', record.product_id.id)
            ]
            pl_line_list = self.env['purchase.order.line']._read_group(pl_domain, ['product_id', 'id'], ['qty_received:sum', 'product_qty:sum'])
            pl_line_dict = {}
            for pt, pl, val0, val1 in pl_line_list:
                if pt in pl_line_dict:
                    pl_line_dict[pt] += val1 if val0 > val1 else val0
                else:
                    pl_line_dict[pt] = val1 if val0 > val1 else val0
            close_pl_domain = [
                ('pr_middle_ids.pr_line_id', 'in', list(close_pr_line_dict.keys())),
                # ('pr_line_id.state', '=', 'closed'),
                ('state', '!=', 'cancel'),
                ('product_id', '=', record.id),
                ('s_close', '=', False)
            ]
            close_pl_line_list = self.env['purchase.order.line']._read_group(close_pl_domain, ['product_id', 'id'], ['qty_received:sum', 'product_qty:sum'])
            pre_close_pl_line_dict = {}
            don_close_pl_line_dict = {}
            for pt, pl, val0, val1 in close_pl_line_list:
                if pt in pre_close_pl_line_dict:
                    pre_close_pl_line_dict[pt] += val1
                    don_close_pl_line_dict[pt] += val0
                else:
                    pre_close_pl_line_dict[pt] = val1
                    don_close_pl_line_dict[pt] = val0
            # 接收数量  接收数量会进入库存量
            qty_received = round(pl_line_dict.get(record.product_id, 0), 4)

            # 加入单独创建采购单统计数量
            rpl_domain = [('pr_middle_ids', '=', False),
                          ('state', '!=', 'cancel'),
                          ('product_id', '=', record.product_id.id)]
            rpl_line_list = self.env['purchase.order.line']._read_group(rpl_domain,
                                                                        ['product_id'],
                                                                        ['product_qty:sum', 'qty_received:sum'])
            rpl_list_dict = {p: q for _, p, q in rpl_line_list}

            # 未接收数量
            per_product_qty = round(sum(rpl_list_dict.keys(), 0), 4)
            per_close_product_qty = round(sum(pre_close_pl_line_dict.values(), 0), 4)
            pr_product_qty += per_product_qty
            pr_product_qty += per_close_product_qty
            don_received = round(sum(rpl_list_dict.values(), 0), 4)
            don_close_received_qty = round(sum(don_close_pl_line_dict.values(), 0), 4)
            qty_received += don_received
            qty_received += don_close_received_qty
            sum_qty = pr_product_qty - qty_received
            record.transit_qty = record.product_uom._compute_quantity(sum_qty, record.stock_product_uom)  # 在途数
            if record.product_min_qty <= 0:
                record.qty_to_order = 0
                continue
            if record.qty_available > record.product_min_qty:  # 库存数量未处于安全状态
                record.qty_to_order = 0
                continue
            product_qty_1 = record.product_min_qty * record.qty_multiple - record.qty_available - sum_qty
            if record.product_id.uom_id != record.product_id.uom_po_id \
                    and record.product_id.uom_id.uom_type == 'reference' \
                    and record.product_id.uom_id.ratio == 1:
                product_qty_1 = product_qty_1 // record.product_id.uom_po_id.ratio + (
                    1 if product_qty_1 % record.product_id.uom_po_id.ratio else 0
                )

            if product_qty_1 <= 0:
                record.qty_to_order = 0
                continue
            if not CHECK_ORDERPOINT_CODE:
                qty = product_qty_1 if product_qty_1 > 0 else 0
                qty_2 = record.product_uom._compute_quantity(qty, record.stock_product_uom)
                record.qty_to_order = qty_2
                continue
            # 增加重新订购规则判断
            product_orderpoint_row = record.product_id.orderpoint_ids.filtered(
                lambda x: x.location_id == record.product_id.storage_location_id \
                          and x.product_min_qty > 0 \
                          and x.product_min_qty <= x.product_max_qty
            )
            if product_orderpoint_row:
                product_min_qty = product_orderpoint_row.product_min_qty
                product_max_qty = product_orderpoint_row.product_max_qty
                if product_qty_1 < product_min_qty:
                    if record.stock_product_uom != record.product_uom:
                        product_min_qty = record.product_uom._compute_quantity(product_min_qty, record.stock_product_uom)
                    record.qty_to_order = product_min_qty
                    continue
                order_qty = (product_qty_1 // product_min_qty) * product_min_qty + product_min_qty if product_qty_1 % product_min_qty else 0
                if order_qty >= product_max_qty:
                    product_max_qty = record.product_uom._compute_quantity(product_max_qty, record.stock_product_uom)
                    record.qty_to_order = product_max_qty
                else:
                    order_qty = record.product_uom._compute_quantity(order_qty, record.stock_product_uom)
                    record.qty_to_order = order_qty
            else:
                qty = product_qty_1 if product_qty_1 > 0 else 0
                qty_1 = record.product_uom._compute_quantity(qty, record.stock_product_uom)
                record.qty_to_order = qty_1

    def action_wizard_purchase(self):
        if not self:
            return
        line_ids = []
        for record in self:
            # if record.qty_to_order <= 0:
            #     continue
            line_ids.append((0, 0, {
                'requisitionpoint_id': record.id,
                'qty_to_order': record.qty_to_order
            }))
        if not line_ids:
            return {
                'type': 'ir.actions.client',
                'tag': 'display_notification',
                'params': {
                    'title': 'Warning',
                    'message': _('No details need to be requisition'),
                    'sticky': False,  # 设置为 False，表示通知不会一直显示
                    'timeout': 5000,  # 设置通知显示的时间（单位：毫秒），此处为 5 秒
                }
            }
        res = self.env['purchase.requisitionpoint.wizard'].create({
            'name': ', '.join(self.mapped('name')),
            'line_ids': line_ids
        })
        return {
            'name': _('Purchase requisition'),
            'type': 'ir.actions.act_window',
            'res_model': 'purchase.requisitionpoint.wizard',
            'view_mode': 'form',
            'target': 'new',
            'res_id': res.id,
            'context': {}
        }
